#!/usr/bin/env python3

import pexpect
import sys
import time
import traceback
import os
import getopt
import json
import re

class expect: 

    bash_prompt = '][$#]'
    p = None

    def usage(self):
        print("expect.py version 1.0")
        print("-h print this message equal --help")
        print('-s equal --ssh=\'{"host":"127.0.0.1","user":"account","password":"password"}\'')
        print('-g equal --git=\'{"dirs":["path1","path2"],"user":"account","password":"password"}\'')
        print('-c equal --cmd=\'["ls -l","ls -al"]\'')

    def _existStatus(self):
        self.p.sendline("echo existStatus=$?")
        self.p.expect([self.bash_prompt], timeout=3) 
        return self.p.before.find("existStatus=0") > -1

    def _ssh(self, ssh):
        ssh = json.loads(ssh)
        ssh_host = ssh.get('host')
        ssh_username = ssh.get('user')
        ssh_password = ssh.get('password')
        self.p = pexpect.spawn('ssh {}@{}'.format(ssh_username, ssh_host), encoding='utf-8')

        self.p.logfile_read = sys.stdout

        try:
            index = self.p.expect(['yes/no', '[pP]assword:', self.bash_prompt], timeout=2)
            if index == 0:
                self.p.sendline('yes')
                self.p.expect('[pP]assword:', timeout=5)
                self.p.sendline(ssh_password)
            elif index == 1:
                self.p.sendline(ssh_password)
                self.p.expect([self.bash_prompt], timeout=3)
        except Exception as e:
            raise Exception("ssh connect fail.")

    def _git(self, git):
        git = json.loads(git)
        git_dirs = git.get('dirs')
        git_username = git.get('user')
        git_password = git.get('password')
        for git in git_dirs:
            self.p.sendline("cd {}".format(git))
            self.p.expect([self.bash_prompt], timeout=3) 
            if not self._existStatus():
                raise Exception("project path not found.")

            # git存储过账号密码直接拉取
            self.p.sendline('git stash && git pull')
            index = self.p.expect(['Username', self.bash_prompt, pexpect.TIMEOUT], timeout=120)
            if index == 0:
                self.p.sendline(git_username)
                self.p.expect('Password', timeout=5)
                self.p.sendline(git_password)
                self.p.expect(self.bash_prompt, timeout=120)
            elif index == 2:
                raise Exception("connect code warehouse fail.")

            if not self._existStatus():
                raise Exception("git pull fail.")

            self.p.sendline('git stash pop')
            self.p.expect([self.bash_prompt], timeout=16) 

    def _cmd(self, cmd):
        cmd = json.loads(cmd)
        for command in cmd:
            self.p.sendline(command)
            self.p.expect(self.bash_prompt, timeout=600)
            if not self._existStatus():
                raise Exception("Command: {}. run fail.".format(command))

    def main(self, ssh, git, cmd):
        self._ssh(ssh)

        if git != '':
            self._git(git)

        if cmd != '':
            self._cmd(cmd)

        if cmd != '':
            cmd = json.loads(cmd)

        self.p.close(force=True)
        #  p.logfile = sys.stdout
        return 0

if __name__ == "__main__":
    p = expect()
    try:
        opts, args = getopt.getopt(sys.argv[1:], 'hs:g:c:', ['help', 'ssh=', 'git='])
    except getopt.GetoptError:
        p.usage()    
        sys.exit(2)

    if opts.__len__() == 0:
        p.usage()
        sys.exit(2)

    ssh = ''
    git = ''
    cmd = ''

    for opt,arg in opts:
        if opt in ('-h', '--help'):
            usage()
            sys.exit(2)
        elif opt in ('-s', '--ssh'):
            ssh = arg
        elif opt in ('-g', '--git'):
            git = arg
        elif opt in ('-c', '--cmd'):
            cmd = arg

    if not ssh:
        p.usage()
        sys.exit(2)

    try:
        p.main(ssh, git, cmd)
    except Exception as e:
        if p.p != None:
            p.p.close(force=True)
        # e.__traceback__()
        print(e)
        sys.stdout.flush()
        os._exit(1)
